/*
 *  Project:            timelyRV_v1.0 -- a RISCV-32IMC SoC.
 *  Module name:        memory_part.
 *  Description:        instr/data memory of timelyRV core.
 *  Last updated date:  2022.05.13.
 *
 *  Copyright (C) 2021-2022 Junnan Li <lijunnan@nudt.edu.cn>.
 *  Copyright and related rights are licensed under the MIT license.
 *
 *  Noted:
 *    This module is used to store instruction & data. And we use
 *      "conf_sel" to distinguish configuring or running mode.
 */

// module memory_part (
//     input                 clk,
//     //* prot a
//     input         [3:0]   wea,
//     input         [31:0]  addra,
//     input         [31:0]  dina,
//     output  wire  [31:0]  douta,
//     //* prot b
//     input         [3:0]   web,
//     input         [31:0]  addrb,
//     input         [31:0]  dinb,
//     output  wire  [31:0]  doutb
// );

//   genvar i_ram;
//   generate
//     for (i_ram = 0; i_ram < 4; i_ram = i_ram+1) begin: mem_part
//       ram_8_4096 mem(
//         .clka   (clk                ),
//         .wea    (wea[i_ram]         ),
//         .addra  (addra[11:0]        ),
//         .dina   (dina[8*i_ram+:8]   ),
//         .douta  (douta[8*i_ram+:8]  ),
//         .clkb   (clk                ),
//         .web    (web[i_ram]         ),
//         .addrb  (addrb[11:0]        ),
//         .dinb   (dinb[8*i_ram+:8]   ),
//         .doutb  (doutb[8*i_ram+:8]  )
//       );
//     end
//   endgenerate


// endmodule

module memory_part_32KB (
    input                 clk,
    input                 rst_n,
    //* prot a
    (* mark_debug = "true"*)input         [3:0]   wea,
    (* mark_debug = "true"*)input         [31:0]  addra,
    (* mark_debug = "true"*)input         [31:0]  dina,
    (* mark_debug = "true"*)output  wire  [31:0]  douta,
    //* prot b
    (* mark_debug = "true"*)input         [3:0]   web,
    (* mark_debug = "true"*)input         [31:0]  addrb,
    (* mark_debug = "true"*)input         [31:0]  dinb,
    (* mark_debug = "true"*)output  wire  [31:0]  doutb
);

  genvar i_ram;
  generate
    for (i_ram = 0; i_ram < 4; i_ram = i_ram+1) begin: mem_part
      `ifdef XILINX_FIFO_RAM
        // ram_8_8192 mem(
        //   .clka   (clk                ),
        //   .wea    (wea[i_ram]         ),
        //   .addra  (addra[12:0]        ),
        //   .dina   (dina[8*i_ram+:8]   ),
        //   .douta  (douta[8*i_ram+:8]  ),
        //   .clkb   (clk                ),
        //   .web    (web[i_ram]         ),
        //   .addrb  (addrb[12:0]        ),
        //   .dinb   (dinb[8*i_ram+:8]   ),
        //   .doutb  (doutb[8*i_ram+:8]  )
        // );
        ram_8_8192 mem(
          .data_a    (dina[8*i_ram+:8]),    //  ram_input.datain_a
          .data_b    (dinb[8*i_ram+:8] ),    //           .datain_b
          .address_a (addra[12:0]), //           .address_a
          .address_b (addrb[12:0]), //           .address_b
          .wren_a    (wea[i_ram]),    //           .wren_a
          .wren_b    (web[i_ram]),    //           .wren_b
          .clock_a   (clk),   //           .clock_a
          .clock_b   (clk),   //           .clock_b
          .rden_a    (!wea[i_ram]),    //           .rden_a
          .rden_b    (!web[i_ram]),    //           .rden_b
          .q_a       (douta[8*i_ram+:8]),       // ram_output.dataout_a
          .q_b       (doutb[8*i_ram+:8])        //           .dataout_b
        );
      `else
        dualportsram8192x8 mem(
          .aclr       (~rst_n             ), //* asynchronous reset
          .address_a  (addra[12:0]        ), //* port A: address
          .address_b  (addrb[12:0]        ), //* port B: address
          .clock      (clk                ), //* port A & B: clock
          .data_a     (dina[8*i_ram+:8]   ), //* port A: data input
          .data_b     (dinb[8*i_ram+:8]   ), //* port B: data input
          .rden_a     (!wea[i_ram]        ), //* port A: read enable
          .rden_b     (!web[i_ram]        ), //* port B: read enable
          .wren_a     (wea[i_ram]         ), //* port A: write enable
          .wren_b     (web[i_ram]         ), //* port B: write enable
          .q_a        (douta[8*i_ram+:8]  ), //* port A: data output
          .q_b        (doutb[8*i_ram+:8]  )  //* port B: data output
          );
      `endif
    end
  endgenerate


endmodule

module memory_part_64KB (
    input                 clk,
    input                 rst_n,
    //* prot a
    (* mark_debug = "true"*)input         [3:0]   wea,
    (* mark_debug = "true"*)input         [31:0]  addra,
    (* mark_debug = "true"*)input         [31:0]  dina,
    (* mark_debug = "true"*)output  wire  [31:0]  douta,
    //* prot b
    (* mark_debug = "true"*)input         [3:0]   web,
    (* mark_debug = "true"*)input         [31:0]  addrb,
    (* mark_debug = "true"*)input         [31:0]  dinb,
    (* mark_debug = "true"*)output  wire  [31:0]  doutb
);

  genvar i_ram;
  generate
    for (i_ram = 0; i_ram < 4; i_ram = i_ram+1) begin: mem_part
      `ifdef XILINX_FIFO_RAM
        // ram_8_16384 mem(
        //   .clka   (clk                ),
        //   .wea    (wea[i_ram]         ),
        //   .addra  (addra[13:0]        ),
        //   .dina   (dina[8*i_ram+:8]   ),
        //   .douta  (douta[8*i_ram+:8]  ),
        //   .clkb   (clk                ),
        //   .web    (web[i_ram]         ),
        //   .addrb  (addrb[13:0]        ),
        //   .dinb   (dinb[8*i_ram+:8]   ),
        //   .doutb  (doutb[8*i_ram+:8]  )
        // );
        ram_8_16384 mem(
          .data_a    (dina[8*i_ram+:8]),    //  ram_input.datain_a
          .data_b    (dinb[8*i_ram+:8]),    //           .datain_b
          .address_a (addra[13:0]), //           .address_a
          .address_b (addrb[13:0]), //           .address_b
          .wren_a    (wea[i_ram]),    //           .wren_a
          .wren_b    (web[i_ram]),    //           .wren_b
          .clock_a   (clk),   //           .clock_a
          .clock_b   (clk),   //           .clock_b
          .rden_a    (!wea[i_ram]),    //           .rden_a
          .rden_b    (!web[i_ram]),    //           .rden_b
          .q_a       (douta[8*i_ram+:8]),       // ram_output.dataout_a
          .q_b       (doutb[8*i_ram+:8])        //           .dataout_b
        );
      `endif
    end
  endgenerate


endmodule

module memory_part_0KB (
  input   wire          clk,
  //* prot a
  input   wire  [3:0]   wea,
  input   wire  [31:0]  addra,
  input   wire  [31:0]  dina,
  output  wire  [31:0]  douta,
  //* prot b
  input   wire  [3:0]   web,
  input   wire  [31:0]  addrb,
  input   wire  [31:0]  dinb,
  output  wire  [31:0]  doutb
);

  assign douta = 32'b0;
  assign doutb = 32'b0;
endmodule